iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
0
Mobile Development

小孩子才做選擇 ! Flutter & React Native 我全都要系列 第 15

[Day15] 與 Firebase 結合之自動上傳 DB 記帳(三)終於可以掃左右兩邊惹

  • 分享至 

  • xImage
  •  

經過一整天的奮鬥終於做出還算能用的發票掃描器了TAT (如果有更好的方法請告訴我,拜託!

我們採用最簡單暴力的方法,以畫面中心線分左右,先紀錄有統ㄧ編號的左側 QRcode 在紀錄右側,相加後上傳DB

https://ithelp.ithome.com.tw/upload/images/20191001/20104220xYlosXK7GW.png

  //參考
  let RawTest = {
    bounds: {
      origin: { x: "165.187563", y: "166.461469" },
      size: { width: "91.109270", height: "94.537594" },
      __proto__: Object,
    },
    data: "VA12528817108100173340000018d000001a10000000082869675fWQkJz5mI0mJ3MNvZGbOmg==:**********:1:1:1:餐品:1:417:",
    rawData: "46c56413132353238383137313038313030313733333430303030303138643030303030316131303030303030303038323836393637356657516b4a7a356d49306d4a334d4e765a47624f6d673d3d3a2a2a2a2a2a2a2a2a2a2a3a313a313a313ae9a490e593813a313a3431373a0ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11ec11",
    target: 419,
    type: "org.iso.QRCode",
  }

以下是實作邏輯A


 求出掃描範圍 h667*w375
  w的一半約 188 =中心點(紅線) 
 > let cameraViewPrintrt = this.state.cameraView_XY.x * 0.5;
 如果QRcode為  w100*h100,左上角的位置為x,右上為x+w100 
 > let x = e.bounds.origin.x;
 > let width = e.bounds.size.width;
 轉數字
 > let num = x * 1 + width * 1;
 判斷右上是否超過中線
 > if (x+w100 < cameraViewPrintrt){///左側 QRcode}
 

我好想直接遮住鏡頭喔....(太廢

以下是實作邏輯B


  ////掃描到SN+第二張的**才關閉相機
 
  if (data.startsWith('**')&&data.length>2) {
    ////我是第二張
  }
   if (!data.startsWith('**')
       &&/[0-9]/.match(data[2-10])
       &&(/[a-z]/.match(data[0&1])) {
    ////我是第一張
  }

求出掃描範圍

 this.state.cameraView_XY={w:375,h:667};
 
 _onLayout(event){
    //使用大括號是為了限制讓結構賦值得到的變量的作用域,因為接來下還要結構解構賦值一次
    {
      //獲取外層View的寬高,以及左上角的坐標值
       令{x,y,width,height} = event.nativeEvent.layout;
       this.setState({cameraView_XY:{“ w”:+ width,“ h”:+ height}})
       // console.warn('通過onLayout得到的寬度:'+ width);
       // console.warn('通過onLayout得到的高度:'+ height);
    }

     //通過維度API獲取View寬高
     讓{width,height} = Dimensions.get('window');
     // console.warn('通過Dimensions得到的寬度:'+ width);
     // console.warn('通過Dimensions得到的高度:'+ height);
  }

小提醒

https://ithelp.ithome.com.tw/upload/images/20191001/20104220B5LUZjQpaH.png

記得使用上圖 React Native 自帶的 Remote Debugging 工具,或是 React Developer Tools ,忘記可以參考下圖

https://ithelp.ithome.com.tw/upload/images/20191001/20104220Q3PeNgNpz0.png

/* eslint-disable prettier/prettier */
import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Text,
  TouchableOpacity,
  Dimensions,
  Alert,
} from 'react-native';
import QRCodeScanner from 'react-native-qrcode-scanner';
import Marker from './Marker/Marker';
let data = null;
const data_Context = React.createContext(data);

const DB = [
  { "num": "25576066", "txt": "1,000萬元" },
  { "num": "19614436", "txt": "20萬元" },
  { "num": "96182420", "txt": "頭獎20萬元" },
  { "num": "47464012", "txt": "頭獎20萬元" },
  { "num": "62781818", "txt": "頭獎20萬元" },
  { "num": "066", "txt": "頭獎20萬元" },
  { "num": "899", "txt": "頭獎20萬元" },
]
import firebase from 'react-native-firebase';


const iosConfig = {
//  你的設定
};

const itHelpApp = firebase.initializeApp(iosConfig);

// itHelpApp.onReady().then((app) => {
//   firebase.app('kittens').auth().signInAnonymously().then((user) => {
//     console.log('kittensApp user ->', user.toJSON());
//   });
// });
export { data_Context }
export default class Scanner extends Component {
  constructor(props) {
    super(props);
    this.state = {
      userToken: "A",
      camera: false,
      A: false,
      camera_state: true,
      myName: null,
      rawData_L: "",
      rawData_R: "",
      cameraView_XY: [],
      AwaitNextBounds: true,

    };
  }

  state = {
    isValid: null,
  }

  updata(docID, data) {
    // let docID = "HQ255760627"
    const ref = firebase.firestore().collection('receipt').doc(docID);
    let SN = this.cutString(data, 10, 2);
    // 也可以获取当前的毫秒级时间戳
    var time = Date.now();
    var date = new Date(time * 1000);
    var dt = date.getFullYear() + "-" + (date.getMonth() < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + "-" + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());



    itHelpApp.onReady().then((app) => {
      app.firestore()
        .runTransaction(async transaction => {
          const doc = await transaction.get(ref);
          if (!doc.exists) {
            transaction.set(ref, { onCreate: dt, timer: time, serialNumber: SN, content: data });
            return null;
          }
        })
        .then(newPopulation => {
          console.log(
            `Transaction successfully committed and new population is '${newPopulation}'.`
          );
        })
        .catch(error => {
          console.log('Transaction failed: ', error);
        });
    });
  }



  componentDidMount() {
    ///生命週期 component 載入前執行
    // this.updata();
    this.setState({
      AwaitNextBounds: true,
    });
  }
  componentWillReceiveProps(nextProps) {
    this.setState({
      camera: nextProps.camera,
    });
  }


  cutString(str, len, start, suffix) {
    if (!str) return "";
    if (len <= 0) return "";
    if (!suffix) suffix = "";
    var templen = 0;
    for (var i = 0; i < str.length; i++) {
      if (str.charCodeAt(i) > 255) {
        templen += 2;
      } else {
        templen++
      }
      if (templen == len) {
        return str.substring(start, i + 1) + suffix;
      } else if (templen > len) {
        return str.substring(start, i) + suffix;
      }
    }
    return str;
  }
  Checkprize(str) {
    for (i = 0; i < 7; i++) {
      let ANS = str.lastIndexOf(DB[i].num);
      if (ANS > 2) {
        let txt = "WIN~~~"
        return txt
      }
      else if (ANS == 0) {
        let txt = "~~~WIN~~~"
        return txt;
      }
    }
  }

  onSuccess = async (e) => {

    data = e.data;
    const dataWithoutSpaces = data.trim();
    let x = e.bounds.origin.x;
    let y = e.bounds.origin.y;
    let width = e.bounds.size.width;
    let cameraViewPrintrt = this.state.cameraView_XY.x * 0.5;
    let num = x * 1 + width * 1;
    console.log(num, cameraViewPrintrt, x, y, width, this.state.cameraView_XY);

    console.log(this.state.AwaitNextBounds);
    if (num < cameraViewPrintrt && this.state.AwaitNextBounds == true) {
      console.log("A");
      if (!data.startsWith('**')
        && !data.startsWith('http')
        && dataWithoutSpaces.length >= 77
      ) {
        console.log("A以驗證");
        this.setState({
          AwaitNextBounds: false,
          rawData_L: dataWithoutSpaces
        }, () => {
          console.log("A以存入");
        });
      }
    }
    else {
      console.log("B");
      if (data.startsWith('**')
        && !data.startsWith('http')
        && dataWithoutSpaces.length > 2
        // && dayjs(dateText).isValid()
      ) {
        console.log("B以驗證");

        this.setState({
          rawData_R: dataWithoutSpaces
        }, () => {
          if (this.state.rawData_L !== "") {
            let data = this.state.rawData_L + this.state.rawData_R;
            let docID = this.cutString(this.state.rawData_L, 10, 0);
            console.log(data);
            Alert.alert(data);
            this.updata(docID, data);
          } else {
            console.log("B以驗證,A還沒來");
          }
        });
        console.warn("OKOKOKOK");
      }
    }
  }

  _onLayout(event) {
      let { x, y, width, height } = event.nativeEvent.layout;
      this.setState({ cameraView_XY: { "x": +width, "y": +height } })
      // console.warn('通过onLayout得到的宽度:' + width);
      // console.warn('通过onLayout得到的高度:' + height);
  }

  render() {
    const { closeScanner } = this.props
    const { isValid } = this.state
    const markerColor = (() => {
      if (isValid === null) { return 'rgb(255, 204, 0)' }
      return isValid ? 'rgb(76, 217, 100)' : 'rgb(255, 59, 48)'
    })()
    const CustomMarker = Marker(markerColor, closeScanner)
    const cameraProps = { captureAudio: false }
    return (
      <View style={styles.container} onLayout={this._onLayout.bind(this)} >
        <QRCodeScanner
          onRead={this.onSuccess}
          topContent={null}
          // reactivate={this.state.camera_state}
          reactivate={true}
          cameraProps={cameraProps}
          showMarker
          fadeIn={false}


          customMarker={CustomMarker}
          cameraStyle={styles.camera}
          //reactivate={false}
          /////////切換頁面時要關閉/開啟
          reactivateTimeout={1500}
          bottomContent={
            <TouchableOpacity style={styles.buttonTouchable} onPress={() => {
              this.setState({ camera_state: !this.state.camera_state })
              this.testForceFun.bind(this)
            }} >
              <Text style={styles.buttonText}>{this.state.camera_state}</Text>
            </TouchableOpacity>
          }
        />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  camera: {
    height: Dimensions.get('window').height,
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'white',
  }, centerText: {
    flex: 1,
    fontSize: 18,
    padding: 32,
    color: '#777',
  },
  textBold: {
    fontWeight: '500',
    color: '#000',
  },
  buttonText: {
    fontSize: 21,
    color: 'rgb(0,122,255)',
  },
  buttonTouchable: {
    padding: 16,
  },
});

上一篇
[Day14] 與 Firebase 結合之自動上傳 DB 記帳(二)
下一篇
[Day16] 與 Firebase 結合之 F.C.M. (媽~我終於搞定 FCM 了)
系列文
小孩子才做選擇 ! Flutter & React Native 我全都要32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言